; HOST Program for AMD 96-4016 Z8000 Monitor
;
; Sourced March '80 by 	Trevor Marshall
;			Elec Eng Dept
;			Uni W.A.
;
; This program was written for a Z80 CPU
; running a CDOS 2.17 Disk Operating System.
;
; It has been modified for 8080 CPU 
; but not fully tested with that CPU
;
; Most code is compatible with other CP/M
; systems, but will have to be tailored
; to the individual's hardware environment
;
; Although the AMD SYS 8/8 uses parallel
;  ports for handshaking the 96-4016 will also
;  support serial I/O and this method is
;  usually preferable.
; The AMD Monitor uses an 8 bit data word with
;  parity generated in software.
; If you cannot configure your HOST USART
;  to that format then you must null the 
;  parity generation with NOPs and the parity
;  checking may be defeated with a prior RET
; Note that the AMD SYS 8/8 appears to have a
;  CP/M compatible operating system
;
BDOS:	EQU	5	;CDOS system call addr
RNEXT:	EQU	14H	;Read next record
WNEXT:	EQU	15H	;Write next record
FCREATE: EQU	16H	;Create a file
RESET:	EQU	0DH	;Reset CDOS
FOPEN:	EQU	0FH	;Open a file
FCLOSE:	EQU	10H	;Close a file
DMA:	EQU	1AH	;Set disk buffer address
FORMAT: EQU	86H	;Format name to FCB
NAK:	EQU	15H	;CTL-U
ENQ:	EQU	5	;CTL-E
ACK:	EQU	6	;CTL-F
SOH	EQU	1	;CTL-A
STX:	EQU	2	;CTL-B	
EOT:	EQU	4	;CTL-D
EOF:	EQU	1AH	;End of file marker byte
;
;THE FOLLOWING EQUATES ARE HARDWARE DEPENDENT
;
CSTATP: EQU	0F7H	;Console driver status port
CDATA:	EQU	0F6H	;Console data port
CRDA:	EQU	2	;RDA bit
CTBE:	EQU	1	;TBE bit
;
	ORG	100H
;
START:	LD	SP,80H
	LD	A,0
	LD	(FLAG),A ;Clear the file opened flag
; Now output system prompt to console
	LD	DE,MSG
	LD	C,9	;Print Buffered Line
	CALL	BDOS
;
MORE:	LD	SP,80H	;Reset Stack Pointer
	LD	A,0
	LD	(CODE),A ;Clear the error code
	CALL	DIALOG	;Wait for an instruction
	LD	A,(NEWCODE) ;2 locs to ease debugging
	LD	(CURCODE),A	;Save it
; Now decode the Function request type
	CP	A,4
	JP	Z,OPEN
	CP	A,5
	JP	Z,CLOSE
	CP	A,6
	JP  	Z,CREATE
	CP	A,7
	JP	Z,READ
	CP	A,8
	JP	Z,WRITE
;
	JP	N7	;If not one of the above instrs
;
; S/R to set up FCB name in FCB block from BFFR data
;
SETUP	LD	A,(REQBFFR) ;Fetch the drive (A - C)
	SUB	A,40H	;A = 01 IN FCB
	LD	(REQBFFR+1),A ;Put drive # in FCB
	LD	HL,REQBFFR+1 ;Point at start of legal code
	LD	DE,FCB	;Point at FCB area
	LD	BC,12	;# of bytes in name & drive
;	LDIR		;Shift name to FCB
; implement the LDIR in 8080 code:
L1:	LD	A,(HL)	;***** THIS CODE HAS NOT
	LD	(DE),A	;   BEEN CHECKED******
	INC	HL
	INC	DE
	DEC	BC
	LD	A,C	;Is BC = 0
	OR	A,B
	JP	NZ,L1
;
	RET
;
;Now try to open file
OPEN:	LD	C,RESET
	CALL	BDOS	;First log off all disks
	CALL	SETUP   ;Set up FCB
	LD	DE,FCB
	LD	C,FOPEN
	CALL	BDOS	;Open file
; Any errors?
	ADD	A,1	;Is a = -1 ?
	JP	Z,N7
; Opened successfully, now can process read or write
	LD	A,0FFH
	LD	(FLAG),A ;Set opened flag
	CALL	TRNS	;Acknowledge
	JP	MORE	;Get next instruction
;
WRITE:	LD	A,(FLAG) ;Check file is created or open
	CP	A,0
	JP	Z,N5 ;no, send error code 3
; Now set the DMA address to BFFR
	LD	C,DMA
	LD	DE,BFFR
	CALL	BDOS
;
	LD	DE,FCB
	LD	C,WNEXT
	CALL	BDOS	;Write the record
	CP	A,1	;entry error
	JP	Z,N5	; send code 3
	CP	A,2
	JP	Z,N7	;Send code 1 if out of space
	CP	0	;OK
	JP	NZ,N8	;Send code 2 for other errors
; Must be OK,wait for next instruction
	CALL	TRNS
	JP	MORE
;
CLOSE:	LD	A,(FLAG) ;Dont close an unopened file
	CP	0
	JP	Z,N5	;not open
	LD	C,FCLOSE
	LD	DE,FCB
	CALL	BDOS
	CP	A,0FFH
	JP	Z,N7	;A=FF means not found
	LD	A,0
	LD	(FLAG),A ;Clear the open file flag
	LD	(CODE),A ;Clr error flag
	JP	N10
N7:	LD	A,1	;Send error code 1
	JP	N6
N8:	LD	A,2	;Send error code 2
	JP	N6
N5:	LD	A,3	;Send error code 3
N6:	LD	(CODE),A ;File not open or created
N10:	CALL	TRNS
; Omit the following for 8080 CP/M
;	LD	C,96H	;Call to CDOS 2.17 to turn
;	CALL	BDOS	; drive motors off
	JP	MORE
;
READ:	LD	A,(FLAG) ;Is file open ?
	CP	0
	JP	NZ,N2 ;Yes
	LD	C,RESET	;No,open it
	CALL	BDOS
	CALL	SETUP
	LD	DE,FCB
	LD	C,FOPEN
	CALL	BDOS
	ADD	A,1
	JP	Z,N5   ;type 3 error, not found
	LD	A,0FFH
	LD	(FLAG),A ;Set open flag
; File opened now read record
N2:	LD	C,DMA	;set CDOS DMA addr to bffr
	LD	DE,BFFR
	CALL	BDOS
	LD	C,RNEXT	;read next record
	LD	DE,FCB
	CALL	BDOS
; Now process error codes
	CP	0	;1 = <EOF>
	JP	Z,M1  
; Must be 1, End Of File
; Note that this error is only returned AFTER an
; abortive attempt to fetch the next sector, and
; <EOF> within data is transferred normally, so
; ASM will give errors unless a QUIT instruction
; is used to end the source file.
	LD	A,1
	LD	(CODE),A
	CALL	TRNS	;Dont send any data
	JP	MORE
M1:	CALL	SEND	;Transmit normal data
	JP	MORE
;
CREATE:	LD	A,(FLAG) ;Is file open?
	CP	0
	JP	NZ,N5	;Yes send error code 3
	LD	C,RESET	;Log off all disks
	CALL	BDOS	;Prior to directory operations
	CALL	SETUP
; First check if a file already exists with this name
; Dont delete it,as it may be a mistaken command
	LD	DE,FCB
	LD	C,11H	;Search Directory cmd
	CALL	BDOS
	CP	A,0FFH	
	JP	Z,MI3	;Entry was not found
	LD	A,(HL)	;Fetch the first directory byte
	CP	A,0E5H	;Is it erased
	JP	NZ,N5	;No, send error
MI3:	LD	C,FCREATE
	LD	DE,FCB
	CALL	BDOS
	CP	A,0FFH
	JP	Z,N7	;Send error code 1
	CALL	TRNS
	LD	A,0FFH
	LD	(FLAG),A ;Set the open flag
	JP	MORE
;
;
; S/R to accomplish I/O
; N.B. THESE WILL BE HARDWARE DEPENDENT
CSTAT:	IN	A,CSTATP
	AND	CRDA
	RET	Z
	LD	A,-1
	RET
;
CHIN:	CALL	CSTAT
	JP	Z,CHIN
	IN	A,CDATA
	AND	7FH	;Strip off parity bit
	RET
;
CRDY:	IN	A,CSTATP
	AND	CTBE
	RET	Z
	LD	A,-1
	RET
;
COUT:	PUSH	AF
C1:	CALL	CRDY
	JP	Z,C1
	POP	AF
	OUT	CDATA,A
	RET
;
;
; S/R DIALOG to talk to Z8000
DIALOG: LD	HL,0FFFFH ;Load a delay value to HL
; We will decrement HL until 0, then switch the
; disk drive motors off
DI1:	CALL	CSTAT
	JP	NZ,DIA2 ;Have input,exit motor loop
	DEC	HL
	LD	A,L	;No flag setting after DEC HL
	OR	H
	JP	NZ,DI1	;Try the loop again
; Have now waited long enough, assume Z8000 done
;	LD	C,96H	;Call to CDOS 2.17 to turn
;	CALL	BDOS	; drive motors off
	JP	DIA2
KNACK:	LD	A,NAK
	CALL	COUT
	JP	DIALOG ;Service motors
DIA2:	CALL	CHIN
	CP	ENQ
	JP	NZ,KNACK ;Only <ENQ> is valid
ACKNL:	LD	A,ACK
	CALL	COUT
RECVE:	LD	HL,REQBFFR
	CALL	CHIN
	CP	SOH	;Answer should be <SOH>
	JP	NZ,FLUSH
	CALL	CHIN	;FUNCTION REQUEST CODE 
	SUB	A,30H
	LD	(NEWCODE),A
; We will just receive chars and store them in req bffr
RECVA:	CALL	CHIN
	CP	A,EOT
	JP	Z,RECVB	;Message ends with <EOT>
	CP	A,STX
	JP	Z,RECVA	;Discard it
; Now process two hex bytes
	SUB	30H	;Pseudo-Hex format is used
; Cabt SLA C in 8080, so rewrite
	SCF
	CCF
	RLA
	SCF
	CCF
	RLA
	SCF
	CCF
	RLA
	SCF
	CCF
	RLA
	LD	C,A	;Save first hex digit
	CALL	CHIN
;	SLA	C
;	SLA	C
;	SLA	C
;	SLA	C
	SUB	A,30H
	AND	A,0FH	;Mask off upper nibble
	ADD	A,C	;Now have Hex digit
	LD	(HL),A
	INC	HL
	LD	A,L
	CP	REQBUFFEND AND 0FFH
	JP	NZ,RECVA
	LD	A,H
	CP	REQBUFFEND SHR 8
	JP	NZ,RECVA
	LD	HL,BFFR	;Now point at data buffer
	JP	RECVA
;
RECVB:	LD	A,ACK
	CALL	COUT
	RET
;
;FLUSH routine to discard all input characters
; up to the next <EOT> after an input error
;
FLUSHB:	LD	A,NAK
	CALL	COUT	;Send a <NAK>
FLUSH:	CALL	CHIN 
	CP	EOT	;EOT means end of input
	JP	NZ,FLUSHB ;Continue to flush
	JP	DIALOG	;Try to fetch the data again
;
; S/R to transmit code,response & data in 96-4016 format
;
SEND:   LD	A,ENQ	
	CALL	COUT	;Ask permission to send
SENDA: 	CALL	CHIN
	CP	A,ACK	;Must reply with <ACK>
	JP	NZ,SEND  
SENDB: 	LD	A,SOH
	CALL	COUT
	LD	A,(CURCODE)
	ADD	A,30H
	CALL	COUT	;Transmit the Function Code
	LD	A,STX
	CALL	COUT
	LD	A,'0'	;Error codes, first is zero
	CALL	COUT
	LD	A,(CODE) ;Second code byte
	ADD	'0'
	CALL	COUT
; Now transmit text
	LD	HL,BFFR
LP4:	LD	A,(HL)
	LD	C,A	;Save it
	AND	A,0F0H
; Cant SRA A in 8080,
;	SRA	A
;	SRA	A
;	SRA	A
;	SRA	A
	SCF
	CCF
	RRA
	SCF
	CCF
	RRA
	SCF
	CCF
	RRA
	SCF
	CCF
	RRA
	ADD	A,'0'	;Get in Pseudo-Hex 
	CALL	COUT
	LD	A,C
	AND	A,0FH
	ADD	'0'
	CALL	COUT
	INC	HL
	LD	A,L
	CP	[BUFFEND AND 0FFH]
	JP	NZ,LP4
	LD	A,H	;L was equal,test H
	CP	A,[BUFFEND SHR 8]
	JP	NZ,LP4
;Now have finished buffer
J4:	LD	A,EOT
	CALL	COUT
; Now wait for <ACK>
	CALL	CHIN
	CP	ACK
	RET	Z
	JP	SEND  
;
;
; S/R to transmit code and response only to 96-4016
;
TRNS:	LD	A,ENQ	
	CALL	COUT	;Ask permission to send
TRNSA:	CALL	CHIN
	CP	A,ACK	;Must reply with <ACK>
	JP	NZ,TRNS
TRNSB:	LD	A,SOH
	CALL	COUT
	LD	A,(CURCODE)
	ADD	A,30H
	CALL	COUT	;Transmit the Function Code
	LD	A,STX
	CALL	COUT
	LD	A,'0'	;Error codes, first is zero
	CALL	COUT
	LD	A,(CODE) ;Second code byte
	ADD	'0'
	CALL	COUT
	LD	A,EOT
	CALL	COUT
; Now wait for <ACK>
	CALL	CHIN
	CP	ACK
	RET	Z
	JP	TRNS
;
MSG:	DB	0DH,0AH,'Z8000 HOST Communication Program'
	DB	' between CDOS and AMD 96-4016',0DH,0AH
	DB	0DH,0AH,'       '
	DB	'Contact Trevor Marshall for operating'
	DB	' proceedures.',0DH,0AH,'$'
REQBFFR DS	13
REQBUFFEND EQU	$
BFFR:	DS	128
BUFFEND EQU 	$
CURCODE DS	1	;Current operation code
NEWCODE DS	1	;New operation code
FCB:	DS	33	;FCB area
CODE    DS	1	;Operation status code
FLAG	DS	1	;0 means file is NOT OPEN
	NOP
	END 	START
